package logic

import (
	"context"
	"errors"
	"github.com/zeromicro/go-zero/core/logx"
	"microdemo/restful/bff/internal/svc"
	"microdemo/restful/bff/internal/types"
	"microdemo/service/order/order"
	"microdemo/service/stock/stock"
	"microdemo/service/user/user"
	"strconv"
)

type GetLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLogic {
	return &GetLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetLogic) Get(req *types.BffReq) (resp *types.BffReqResp, err error) {
	// 定义 rpc 接口响应通道和错误通道
	results1 := make(chan *user.UserResponse)
	results2 := make(chan *order.OrderResponse)
	results3 := make(chan *stock.StockResponse)
	errorsChan := make(chan error, 3)
	// rpc 获取用户信息
	go func(r chan<- *user.UserResponse, e chan error) {
		userResponse, err := l.svcCtx.UserRpc.GetUser(context.Background(), &user.IdRequest{
			Id: req.UserId,
		})
		if err != nil {
			e <- err
		}
		r <- userResponse
	}(results1, errorsChan)
	// rpc 获取订单信息
	go func(r chan<- *order.OrderResponse, e chan error) {
		orderResponse, err := l.svcCtx.OrderRpc.GetOrder(context.Background(), &order.OrderIdRequest{
			Id: "order001",
		})
		if err != nil {
			e <- err
		}
		r <- orderResponse
	}(results2, errorsChan)
	// rpc 获取库存信息
	go func(r chan<- *stock.StockResponse, e chan error) {
		stockResponse, err := l.svcCtx.StockRpc.GetStock(context.Background(), &stock.StockIdRequest{
			Id: "stock001",
		})
		if err != nil {
			e <- err
		}
		r <- stockResponse
	}(results3, errorsChan)
	// 阻塞等待并组装返回信息
	userResponse := <-results1
	orderResponse := <-results2
	stockResponse := <-results3
	// 注意：位置不能变，否则因为没有阻塞等待提前关闭通道而报异常
	close(errorsChan)
	var reErr error
	for err2 := range errorsChan {
		logx.Errorf("组装返回信息请求异常：", err2)
		// 如果有多个任务导致错误，使用 errors 的 Join 函数处理
		reErr = errors.Join(reErr, err2)
	}
	if reErr != nil {
		return nil, reErr
	}
	return &types.BffReqResp{
		IdInt64: types.IdInt64{
			Id: req.Id,
		},
		UserInfo: types.UserResp{
			Id:     userResponse.Id,
			Name:   userResponse.Name,
			Gender: userResponse.Gender,
		},
		StockInfo: types.StockResp{
			Id:   stockResponse.Id,
			Name: stockResponse.Name,
			Num:  stockResponse.Num,
		},
		OrderInfo: types.OrderResp{
			Id: orderResponse.Id,
			No: orderResponse.No,
		},
	}, nil
}

func (l *GetLogic) AddUserHandler(req *types.UserAdd) (resp *types.IdInt64, err error) {
	addUser, err := l.svcCtx.UserRpc.AddUser(context.Background(), &user.AddUserRequest{
		Name:   req.Name,
		Gender: req.Gender,
	})
	if err != nil {
		return nil, err
	}
	return &types.IdInt64{Id: addUser.Id}, nil
}

func (l *GetLogic) ModifyUserHandler(req *types.UserModify) (resp *types.UserResp, err error) {
	modifyUser, err := l.svcCtx.UserRpc.UpdateUser(context.Background(), &user.UpdateUserRequest{
		Id:     req.Id,
		Name:   req.Name,
		Gender: req.Gender,
	})
	if err != nil {
		return nil, err
	}
	return &types.UserResp{
		Id:     modifyUser.Id,
		Name:   modifyUser.Name,
		Gender: modifyUser.Gender,
	}, nil
}

func (l *GetLogic) DeletedUserHandler(req *types.IdInt64) (resp bool, err error) {
	_, err = l.svcCtx.UserRpc.DeletedUser(context.Background(), &user.IdRequest{
		Id: strconv.FormatInt(req.Id, 10),
	})
	if err != nil {
		return false, err
	}
	return true, nil
}
